package com.galaxy.payment.service.impl;

import com.galaxy.common.core.exception.ServiceException;
import com.galaxy.payment.api.RemoteOrderService;
import com.galaxy.payment.api.RemoteUserService;
import com.galaxy.payment.config.WxPayConfig;
import com.galaxy.payment.domain.OrderBo;
import com.galaxy.payment.domain.PaymentRecord;
import com.galaxy.payment.domain.bo.AccountFlowBo;
import com.galaxy.payment.domain.bo.PaymentBo;
import com.galaxy.payment.domain.convert.PaymentRecordConvert;
import com.galaxy.payment.domain.vo.PaymentRecordVo;
import com.galaxy.payment.service.IAccountFlowService;
import com.galaxy.payment.service.IPaymentRecordService;
import com.galaxy.payment.service.IWxPayService;
import com.galaxy.payment.utils.WxPayUtils;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 微信支付服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WxPayServiceImpl implements IWxPayService {

    private final WxPayConfig wxPayConfig;
    private final WxPayUtils wxPayUtils;
    private final IPaymentRecordService paymentRecordService;

    @Autowired
    private IAccountFlowService iAccountFlowService;

    @Autowired
    private RemoteOrderService remoteOrderService;

    @Autowired
    private RemoteUserService remoteUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentRecordVo createMiniPay(PaymentBo bo) {
        try {
            PaymentRecordVo paymentRecord = paymentRecordService.getPaymentRecordByOrderNo(bo.getOrderNo());
            if(paymentRecord != null && paymentRecord.getStatus() == 2){
                Map<String, String> payParams = new HashMap<>();
                payParams.put("nonceStr","ORDER_ALREADY_PAID");
                paymentRecord.setPayParams(payParams);
                return paymentRecord;
            }
            // 1. 创建支付记录
            if(paymentRecord == null){
                paymentRecord = paymentRecordService.createPayment(bo);
                if (paymentRecord == null) {
                    throw new ServiceException("创建支付记录失败");
                }
            }

            // 2. 获取用户openid
            String openid = wxPayUtils.getOpenidByUserId(paymentRecord.getUserId());
            if (!StringUtils.hasText(openid)) {
                throw new ServiceException("获取用户openid失败");
            }

            // 3. 调用微信支付统一下单接口
            PrepayWithRequestPaymentResponse response = wxPayUtils.createJsapiPayment(
                paymentRecord.getOrderNo(),
                "商品购买",
                paymentRecord.getPaymentAmount(),
                openid,
                bo.getType()
            );
            if(response != null){
                // 4. 更新支付记录
                PaymentBo updateBo = new PaymentBo();
                updateBo.setPayNo(paymentRecord.getPayNo());
                updateBo.setId(paymentRecord.getId());
                updateBo.setTradeNo(response.getPackageVal());
                paymentRecordService.updateByBo(updateBo);

                // 5. 构建返回参数
                Map<String, String> payParams = new HashMap<>();
                payParams.put("timeStamp", response.getTimeStamp());
                payParams.put("nonceStr", response.getNonceStr());
                payParams.put("package", response.getPackageVal());
                payParams.put("signType", response.getSignType());
                payParams.put("paySign", response.getPaySign());
                paymentRecord.setPayParams(payParams);
            }else{
                Map<String, String> payParams = new HashMap<>();
                payParams.put("nonceStr","ORDER_ALREADY_PAID");
                paymentRecord.setPayParams(payParams);
            }


            return paymentRecord;
        } catch (Exception e) {
            log.error("创建小程序支付失败", e);
            throw new ServiceException("创建小程序支付失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentRecordVo queryPayResult(String payNo,String type) {
        try {
            // 1. 查询支付记录
            PaymentRecordVo paymentRecord = paymentRecordService.getPaymentRecordByOrderNo(payNo);
            if (paymentRecord == null) {
                throw new ServiceException("支付记录不存在");
            }

            // 2. 如果支付已完成，直接返回
            if (paymentRecord.getStatus() == 2) {
                return paymentRecord;
            }

            // 3. 调用微信支付查询接口
            Transaction transaction = wxPayUtils.queryOrderStatus(payNo);

            // 4. 更新支付状态
            if (transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
                AccountFlowBo accountFlowBo = new AccountFlowBo();
                accountFlowBo.setUserId(paymentRecord.getUserId());
                accountFlowBo.setOrderNo(paymentRecord.getOrderNo());
                accountFlowBo.setFlowType(Objects.equals(type, "充值") ? 1 : 2);
                accountFlowBo.setAmount(Objects.equals(type, "充值")?paymentRecord.getPaymentAmount():paymentRecord.getPaymentAmount().negate());

                accountFlowBo.setBalance(BigDecimal.ZERO);
                accountFlowBo.setDescription(Objects.equals(type, "充值") ? "充值余额" : "微信支付购买商品");
                iAccountFlowService.insertByBo(accountFlowBo);

                PaymentBo updateBo = new PaymentBo();
                updateBo.setPayNo(paymentRecord.getPayNo());
                updateBo.setStatus(2); // 支付成功
                updateBo.setSuccessTime(new Date());
                updateBo.setId(paymentRecord.getId());
                paymentRecordService.updateByBo(updateBo);
                OrderBo orderBo =  new OrderBo();
                orderBo.setId(paymentRecord.getOrderId());
                orderBo.setPayType(1);
                orderBo.setStatus(2);
                orderBo.setOutTradeNo(paymentRecord.getPayNo());
                orderBo.setPayTime(LocalDateTime.now());
                remoteOrderService.edit(orderBo);


                return paymentRecordService.getPaymentRecordByOrderNo(payNo);
            }

            return paymentRecord;
        } catch (Exception e) {
            log.error("查询支付结果失败", e);
            throw new ServiceException("查询支付结果失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean closePay(String payNo) {
        try {
            // 1. 查询支付记录
            PaymentRecordVo paymentRecord = paymentRecordService.getPaymentRecord(payNo);
            if (paymentRecord == null) {
                throw new ServiceException("支付记录不存在");
            }

            // 2. 如果支付已完成，不能关闭
            if (paymentRecord.getStatus() == 2) {
                throw new ServiceException("支付已完成，不能关闭");
            }

            // 3. 调用微信支付关单接口
            CloseOrderRequest closeRequest = new CloseOrderRequest();
            closeRequest.setMchid(wxPayConfig.getMerchantId());
            closeRequest.setOutTradeNo(payNo);
            wxPayUtils.getJsapiService().closeOrder(closeRequest);

            // 4. 更新支付状态
            PaymentBo updateBo = new PaymentBo();
            updateBo.setPayNo(payNo);
            updateBo.setStatus(3); // 已关闭
            return paymentRecordService.updateByBo(updateBo);
        } catch (Exception e) {
            log.error("关闭支付订单失败", e);
            throw new ServiceException("关闭支付订单失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refund(String payNo, String reason) {
        try {
            // 1. 查询支付记录
            PaymentRecordVo paymentRecord = paymentRecordService.getPaymentRecord(payNo);
            if (paymentRecord == null) {
                throw new ServiceException("支付记录不存在");
            }

            // 2. 如果支付未完成，不能退款
            if (paymentRecord.getStatus() != 2) {
                throw new ServiceException("支付未完成，不能退款");
            }

            // 3. 构建退款请求


            // 5. 更新支付状态
            PaymentBo updateBo = new PaymentBo();
            updateBo.setPayNo(payNo);
            updateBo.setStatus(4); // 已退款
            return paymentRecordService.updateByBo(updateBo);
        } catch (Exception e) {
            log.error("申请退款失败", e);
            throw new ServiceException("申请退款失败：" + e.getMessage());
        }
    }
}
